home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/python
-
- # (c) 2007 Canonical Ltd.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along
- # with this program; if not, write to the Free Software Foundation, Inc.,
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
- '''KDE user interface implementation.'''
-
- import sys
- import os.path
- import re
-
- from PyQt4.QtCore import SIGNAL
- from PyQt4.QtCore import QTimer
- import PyQt4.QtGui
- from PyKDE4.kdecore import *
- from PyKDE4.kdeui import *
-
- import jockey.ui
- from jockey.oslib import OSLib
- import jockey.kdeui.ui_ManagerWindowKDE4
- import jockey.kdeui.ui_ProgressDialog
- import jockey.kdeui.ui_LicenseDialog
-
- class JockeyTreeWidgetItem(PyQt4.QtGui.QTreeWidgetItem):
- '''A subclassed QTreeWidgetItem that can store its handler.
-
- A workaround for the Model/View framework which will be implemented later
- on.
- '''
- def __init__(self, handler_id, parent=None):
- super(JockeyTreeWidgetItem, self).__init__(parent)
- self.handler_id = handler_id
-
- class ManagerWindowKDE4(PyQt4.QtGui.QDialog, jockey.kdeui.ui_ManagerWindowKDE4.Ui_manager_window):
- def __init__(self, parent=None):
- super(ManagerWindowKDE4, self).__init__(parent)
- self.setupUi(self)
-
- class ProgressDialog(PyQt4.QtGui.QDialog, jockey.kdeui.ui_ProgressDialog.Ui_progress_dialog):
- def __init__(self, parent=None):
- super(ProgressDialog, self).__init__(parent)
- self.setupUi(self)
-
- class LicenseDialog(PyQt4.QtGui.QDialog, jockey.kdeui.ui_LicenseDialog.Ui_dialog_licensetext):
- def __init__(self, parent=None):
- super(LicenseDialog, self).__init__(parent)
- self.setupUi(self)
-
- class KDEUI(jockey.ui.AbstractUI):
- '''KDE user interface implementation.'''
-
- keyb_trans_re = re.compile('(?<! _) _ (?! _)', re.X)
-
- def convert_keybindings(self, str):
- return self.keyb_trans_re.sub('&', str)
-
- def ui_init(self):
- '''Initialize UI.'''
-
- self.mw = ManagerWindowKDE4()
-
- # set icon
- if os.path.exists('/usr/share/icons/hicolor/22x22/apps/jockey-kde.png') and os.path.exists('/usr/share/icons/hicolor/48x48/apps/jockey-kde.png'):
- icon = KIcon('jockey-kde.png')
- largeIcon = KIcon('jockey-kde.png')
- # Not a good idea to use KIcon for fallback since KIcon doesn't take
- # absolute paths...
- elif os.path.exists('data/icons/22x22/apps/jockey-kde.png') and os.path.exists('data/icons/48x48/apps/jockey-kde.png'):
- icon = KIcon('data/icons/22x22/apps/jockey-kde.png')
- largeIcon = KIcon('data/icons/48x48/apps/jockey-kde.png')
-
- # load tray icon
- # not visible yet
- self.trayicon = KSystemTrayIcon(icon, self.mw)
- #print self.trayicon
- # connect the tray signals
- self.mw.connect(self.trayicon,
- SIGNAL('activated(QSystemTrayIcon::ActivationReason)'),
- self.open_app)
-
- self.mw.connect(self.trayicon,
- SIGNAL('messageClicked()'), self.open_app)
-
- # Set window icon
- self.mw.setWindowIcon(KIcon(icon))
-
- # connect signals
- self.mw.connect(self.mw.buttonBox, SIGNAL('rejected()'), self.on_buttonBox_rejected)
- self.mw.connect(self.mw.buttonBox, SIGNAL('helpRequested()'),
- self.on_buttonBox_helpRequested)
-
- self.mw.connect(self.mw.button_toggle, SIGNAL('clicked()'),
- self.on_button_toggle_clicked)
-
- # Set Logo
- self.mw.logo_image.setPixmap(largeIcon.pixmap(48,48))
-
- # disable help button if help is not available
- if not OSLib.inst.ui_help_available(self):
- self.mw.buttonBox.setStandardButtons(KDialogButtonBox.Close)
-
- # load progress dialog UI
- self.progress_ui = ProgressDialog(self.mw)
-
- # load license dialog UI
- self.dialog_licensetext_ui = LicenseDialog(self.mw)
- self.dialog_licensetext_ui.setWindowTitle(self.string_license_dialog_title)
-
- # connect signals
- self.mw.connect(self.mw.linkbutton_licensetext, SIGNAL('leftClickedUrl()'),
- self.on_linkbutton_licensetext_leftClickedUrl)
-
-
- # connect the signals
- self.progress_ui.connect(self.progress_ui.buttonCancel, SIGNAL('clicked()'),
- self.on_buttonCancel_clicked)
-
- # we have to connect this signal here, but that still is a
- # bad solution.
- self.mw.connect(self.mw.treeview_drivers,
- SIGNAL('currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem* )'),
- self.on_treeview_drivers_currentItemChanged)
-
- self.mw.setWindowTitle(self.main_window_title())
- self.mw.label_license_label.setText(self.string_license_label)
- self.mw.linkbutton_licensetext.setText('(%s)' % self.string_details)
-
- def set_help_button_visible(self, buttonbox, is_visible):
- for myButton in buttonbox.buttons():
- # if it is a help button
- if buttonbox.buttonRole(myButton) == 4:
- myButton.setVisible(is_visible)
-
- def ui_show_main(self):
- '''Show the main window.'''
-
- # update tree model
- self.update_driver_info_ui(None)
- self.update_tree_model()
-
- # show help button?
- if not OSLib.inst.ui_help_available(self):
- self.set_help_button_visible(self.mw.buttonBox, False)
-
- self.mw.show()
-
- def ui_main_loop(self):
- '''Main loop for the user interface.'''
-
- KApplication.exec_() #MIGHT NEED TO INITIALISE KApp at some point
-
- def error_message(self, title, text):
- '''Present an error message box.'''
-
- text = '<h3>' + title + '</h3>' + text
-
- msgbox = KMessageBox.sorry(self.mw, text, title, KMessageBox.Notify)
-
- # KMessageBox returns nothing in this case, but when it closes we can return true (I think...)
- return True
-
-
- def confirm_action(self, title, text, subtext=None, action=None):
- '''Present a confirmation dialog.
-
- If action is given, it is used as button label instead of the default
- 'Continue'. Return True if the user confirms, False otherwise.
- '''
- text = '<h3>%s</h3>' % text
- if subtext:
- text += subtext
- text = text.replace('\n', '<br/>')
- # FIXME: action doesn't replace the default button label "continue".
- # The Hardy release doesn't either though...
- msgbox = KMessageBox.warningContinueCancel(self.mw, text, title)
-
- # If continue was clicked msgbox returns 5. It returns 2 when cancel is clicked.
- if msgbox == 5:
- return True
- elif msgbox == 2:
- return False
-
- def ui_notification(self, title, text):
- '''Present a notification popup.
-
- This should preferably create a tray icon. Clicking on the tray icon or
- notification should run the GUI.
- '''
- self.trayicon.show()
- self.ui_idle()
- QTimer.singleShot(2000, lambda: self.trayicon.showMessage(title, text))
-
- def open_app(self, argument = None):
- '''Tray activation callback, launch the elevated app.'''
-
- # TODO: this only works with a KDE PolicyKit, which does not exist yet;
- # so work around by calling it through kdesu
- # self.ui_show_main()
- argv = ['/usr/lib/kde4/libexec/kdesu', sys.argv[0]]
- try:
- import subprocess
- subprocess.call(argv, close_fds=True)
- except OSError, e:
- logging.error('could not execute %s: %s' % (str(argv), e.message))
- sys.exit(0)
-
- def ui_idle(self):
- '''Redraw app while external package manager progresses.'''
-
- KApplication.processEvents()
-
- def ui_progress_start(self, title, description, total):
- '''Create a progress dialog.'''
-
- # hint: you achieve the indeterminate value by setting
- # both min and max to 0
-
- if(total == -1):
- total = 0
-
- self.progress_ui.progressBar.setRange(0, total)
-
- # set translations
- self.progress_ui.setWindowTitle(title)
- self.progress_ui.description.setText(description)
-
- self.progress_ui.show()
- self.cancel_progress = False
-
- def ui_progress_update(self, current, total):
- '''Update status of current progress dialog.
-
- current/total specify the number of steps done and total steps to
- do, or -1 if it cannot be determined. In this case the dialog should
- display an indeterminated progress bar (bouncing back and forth).
-
- This should return True to cancel, and False otherwise.
- '''
- if current < 0 or total < 0:
- # indeterminated mode
- if self.progress_ui.progressBar.maximum() != 0:
- self.progress_ui.progressBar.setRange(0, 0)
- else:
- self.progress_ui.progressBar.setRange(0, total)
- self.progress_ui.progressBar.setValue(current)
-
- return self.cancel_progress
-
- def ui_progress_finish(self):
- '''Close the current progress dialog.'''
-
- self.progress_ui.close()
-
- # callbacks
- def on_buttonBox_rejected(self):
- '''Callback for clicked Close button.'''
-
- self.mw.close()
- # Ugly hack since pyqt doesn't seem to exit the main loop
- # without segfaulting since the class is not a subclass of
- # a QDialog or of something related to QT.
- if __name__ == '__main__':# don't break the tests
- sys.exit()
-
- def on_buttonBox_helpRequested(self):
- '''Callback for clicked Help button.'''
-
- OSLib.inst.ui_help(self)
- return True
-
- def on_button_toggle_clicked(self):
- self.mw.treeview_drivers.setDisabled(True)
-
- item = self.mw.treeview_drivers.currentItem()
-
- if item:
- h_id = item.handler_id
-
- if self.set_handler_enable(h_id, 'toggle', False):
- self.update_tree_model()
- self.mw.treeview_drivers.setDisabled(False)
- return True
-
- def on_treeview_drivers_currentItemChanged(self, old, new):
- if new:
- item = self.mw.treeview_drivers.currentItem()
- if item:
- h_id = item.handler_id
- self.update_driver_info_ui(h_id)
- return True
-
- def on_buttonCancel_clicked(self):
-
- '''Callback for cancelling the progress dialog.'''
-
- self.cancel_progress = True
- return True
-
- def update_tree_model(self):
- '''Updates the tree model with up to date information.
-
- Unfortunately, due to time contraints, the KDE frontend does not use a
- Model/View framework yet.'''
-
- # we have to workaround the model/view with a subclassed
- # QTreeWidgetItem
-
- self.mw.label_heading.setText('<b>%s</b><br/><br/>%s' % self.main_window_text())
-
- # keep current selection if we have one
- cur_item = self.mw.treeview_drivers.currentItem()
- if cur_item:
- cur_handler = cur_item.handler_id
- cur_item = None
- else:
- cur_handler = None
-
- # first clear the list
- self.mw.treeview_drivers.clear()
-
- # then repopulate
- ha = []
- parents = {}
- for h_id in self.get_displayed_handlers():
- info = self.get_ui_driver_info(h_id)
- if info['needs_reboot']:
- icon = KIcon('system-restart')
- elif info['enabled']:
- icon = KIcon('jockey-enabled')
- else:
- icon = KIcon('jockey-disabled')
-
- # load the item
- # here we make use of the subclassed QTreeWidgetItem
- i = JockeyTreeWidgetItem(h_id, self.mw.treeview_drivers)
- i.setIcon(0, icon)
- i.setText(1, info['name'])
- if h_id == cur_handler:
- cur_item = i
-
- # Sort the items in alphabetical order
- self.mw.treeview_drivers.sortItems (1, PyQt4.QtCore.Qt.AscendingOrder)
-
- # We want to adjust the columns and expand the tree.
- self.mw.treeview_drivers.expandAll()
- self.mw.treeview_drivers.resizeColumnToContents(0)
- self.mw.treeview_drivers.resizeColumnToContents(1)
-
- # if we previously had a selection, restore it, otherwise select the
- # first one
- if not cur_item:
- cur_item = self.mw.treeview_drivers.topLevelItem(0)
- if cur_item:
- self.mw.treeview_drivers.setItemSelected(cur_item, True)
- self.update_driver_info_ui(cur_item.handler_id)
-
- def update_driver_info_ui(self, handler_id):
- '''Update UI elements which show the driver details.
-
- If handler_id is None, then no driver is selected, no information
- shown, and the appropriate controls are disabled.'''
-
- # info = self.get_ui_driver_info(unicode(handler_id))
- info = self.get_ui_driver_info(handler_id)
- self.mw.label_drivername.setText('<b>%s</b>' % info['name'])
- self.current_driver_name = info['name']
- self.mw.textview_description.setText(info['description'])
- if info['certified'] == None:
- self.mw.image_certification.hide()
- elif info['certified']:
- self.mw.image_certification.show()
-
- if os.path.exists('/usr/share/icons/hicolor/scalable/emblems/jockey-certified.svg'):
- certified_icon = KIcon('jockey-certified.svg')
-
- self.mw.image_certification.setPixmap(certified_icon.pixmap(16,16))
- elif os.path.exists('data/icons/scalable/emblems/jockey-certified.svg'):
- certified_icon = PyQt4.QtGui.QIcon('data/icons/scalable/emblems/jockey-certified.svg')
-
- self.mw.image_certification.setPixmap(certified_icon.pixmap(16,16))
- else:
- self.mw.image_certification.show()
-
- warning_icon = KIcon('dialog-warning')
- self.mw.image_certification.setPixmap(warning_icon.pixmap(16,16))
-
- self.mw.label_certification.setText(info['certification_label'])
-
- if info['free'] == None:
- self.mw.image_license.hide()
- self.mw.label_license_label.hide()
- elif info['free']:
- self.mw.image_license.show()
- self.mw.label_license_label.show()
- self.mw.image_license.setPixmap(KIcon('jockey-free').pixmap(16,16))
- else:
- self.mw.image_license.show()
- self.mw.label_license_label.show()
-
- if os.path.exists('/usr/share/icons/hicolor/scalable/emblems/jockey-proprietary.svg'):
- proprietary_icon = KIcon('jockey-proprietary.svg')
-
- self.mw.image_license.setPixmap(proprietary_icon.pixmap(16,16))
- elif os.path.exists('data/icons/scalable/emblems/jockey-proprietary.svg'):
- proprietary_icon = PyQt4.QtGui.QIcon('data/icons/scalable/emblems/jockey-proprietary.svg')
- self.mw.image_license.setPixmap(proprietary_icon.pixmap(16,16))
-
- self.mw.label_license.setText(info['license_label'])
-
- if info['license_text']:
- self.mw.linkbutton_licensetext.show()
- self.current_license_text = info['license_text']
- else:
- self.mw.linkbutton_licensetext.hide()
- self.current_license_text = None
- if info['enabled'] == None:
- self.mw.image_enabled.hide()
- elif info['needs_reboot']:
- self.mw.image_enabled.show()
- self.mw.image_enabled.setPixmap(KIcon('system-restart').pixmap(16,16))
- elif info['enabled']:
- self.mw.image_enabled.show()
- self.mw.image_enabled.setPixmap(KIcon('jockey-enabled').pixmap(16,16))
- else:
- self.mw.image_enabled.show()
- self.mw.image_enabled.setPixmap(KIcon('jockey-disabled').pixmap(16,16))
- self.mw.label_status.setText(info['status_label'])
-
- if not info['button_toggle_label']:
- self.mw.button_toggle.setText(self.string_button_enable)
- self.mw.button_toggle.setEnabled(False)
- else:
- self.mw.button_toggle.setEnabled(True)
- self.mw.button_toggle.setText(info['button_toggle_label'])
- if info['enabled']:
- icon = KIcon('jockey-disabled')
- self.mw.button_toggle.setIcon(icon)
- else:
- icon = KIcon('jockey-enabled')
- self.mw.button_toggle.setIcon(icon)
-
- def on_linkbutton_licensetext_leftClickedUrl(self):
- self.dialog_licensetext_ui.label_license_drivername.setText('<b>%s</b>' %
- self.current_driver_name)
- self.dialog_licensetext_ui.textview_license_text.setPlainText(self.current_license_text)
- self.dialog_licensetext_ui.show()
- return True
-
- appName = 'jockey'
- catalog = ''
- programName = ki18n ('Jockey')
- version = '1.0'
- description = ki18n ('Jockey driver manager')
- license = KAboutData.License_GPL
- copyright = ki18n('(c) 2007, 2008 Canonical Ltd')
- text = ki18n ('none')
- homePage = 'https://launchpad.net/jockey'
- #bugEmail = ""
-
- #generates the about data entry from the provided information.
- aboutData = KAboutData(appName, catalog, programName, version, description, license, copyright, text, homePage)
-
- aboutData.addAuthor(ki18n('Martin Pitt'), ki18n('Main author'))
- aboutData.addAuthor(ki18n('Jonathan Thomas'), ki18n('Work on PyQt4 to PyKDE4 port'))
- aboutData.addAuthor(ki18n('Alberto Milone'), ki18n('Work on PyQt4 to PyKDE4 port'))
-
- if __name__ == '__main__':
- # We need a copy of sys.argv for ui.py to use
- argscopy = sys.argv
- # We don't want KCmdLineArgs to parse our cmd line args but it'll need
- # something... Just give it nothing and let ui.py worry about args.
- sys.argv = [""]
-
- KCmdLineArgs.init(sys.argv, aboutData)
- kapp = KApplication()
-
- sys.argv = argscopy
- OSLib.inst = OSLib()
- u = KDEUI()
- sys.exit(u.run())
-